스프링 빈
1. 개요
1. 개요
스프링 프레임워크에서 스프링 빈은 스프링 IoC 컨테이너가 생성과 의존 관계 설정, 생명주기 관리를 담당하는 객체이다. 애플리케이션을 구성하는 핵심 객체를 스프링 IoC 컨테이너에 등록함으로써 개발자는 객체의 생성과 복잡한 의존 관계를 직접 관리하지 않아도 된다.
스프링 빈은 주로 XML 설정 파일, 자바 설정 클래스(@Configuration), 또는 컴포넌트 스캔(@Component) 방식을 통해 컨테이너에 등록된다. 등록된 빈은 컨테이너로부터 필요한 다른 빈을 주입받을 수 있으며, 이를 의존성 주입(DI)이라고 한다. 이는 객체 간의 결합도를 낮추고 테스트 용이성을 높이는 핵심 원리이다.
각 빈은 싱글톤, 프로토타입과 같은 스코프를 가질 수 있으며, 기본적으로 싱글톤 스코프로 관리된다. 이는 애플리케이션 전역에서 해당 빈의 인스턴스를 하나만 공유하여 사용함을 의미한다. 또한 컨테이너는 빈의 초기화와 소멸과 같은 생명주기를 관리할 수 있는 콜백 메커니즘을 제공한다.
결국 스프링 빈은 스프링 프레임워크가 제어의 역전과 의존성 주입이라는 핵심 개념을 실현하는 기본 단위이다. 이를 통해 개발자는 비즈니스 로직 구현에 더 집중할 수 있고, 유연하고 관리하기 쉬운 애플리케이션을 구축할 수 있다.
2. 정의
2. 정의
스프링 빈은 스프링 프레임워크의 핵심인 IoC 컨테이너가 생성과 의존 관계 설정, 생명주기 전반을 관리하는 객체이다. 일반적으로 개발자가 new 키워드로 직접 생성하는 POJO와 달리, 스프링 빈은 컨테이너에 의해 인스턴스화되고 조립되며 애플리케이션 전반에 제공된다.
스프링 빈은 주로 XML 설정 파일, 자바 설정 클래스(@Configuration), 또는 컴포넌트 스캔(@Component) 방식을 통해 컨테이너에 등록된다. 등록된 빈은 컨테이너로부터 의존성 주입을 받아 다른 빈과 협력하며, 싱글톤 스코프를 기본으로 하여 애플리케이션 내에서 일반적으로 하나의 인스턴스로 재사용된다. 이는 메모리 효율성과 일관된 상태 관리를 가능하게 한다.
컨테이너의 관리 하에 있기 때문에, 스프링 빈은 초기화(@PostConstruct 또는 InitializingBean)와 소멸(@PreDestroy 또는 DisposableBean)과 같은 생명주기 콜백을 활용할 수 있다. 또한 필요에 따라 프로토타입 스코프나 웹 관련 스코프(예: 리퀘스트, 세션)로 지정하여 다른 방식으로 인스턴스가 관리되도록 할 수 있다.
결국 스프링 빈은 스프링 애플리케이션을 구성하는 기본 부품으로, 컨테이너에 의해 제어의 역전이 적용되어 느슨한 결합도와 높은 테스트 용이성을 갖는 애플리케이션 개발을 가능하게 한다.
3. 생명주기
3. 생명주기
3.1. 초기화
3.1. 초기화
스프링 빈의 초기화는 스프링 IoC 컨테이너가 빈 객체를 생성한 후, 사용 준비를 완료하는 단계이다. 이 과정은 빈이 의존성 주입을 마친 직후에 발생하며, 주로 빈의 사용을 위해 필요한 추가 설정이나 리소스 할당을 수행한다.
초기화를 위한 가장 일반적인 방법은 InitializingBean 인터페이스를 구현하는 것이다. 이 인터페이스는 afterPropertiesSet()이라는 메서드를 정의하며, 스프링 프레임워크는 모든 속성(의존성)이 주입된 후 이 메서드를 자동으로 호출한다. 또한, XML 설정이나 자바 설정 클래스에서 빈 정의 시 init-method 속성을 지정하여 사용자 정의 초기화 메서드의 이름을 등록하는 방법도 널리 사용된다. 이렇게 지정된 메서드는 컨테이너에 의해 빈의 초기화 단계에서 실행된다.
초기화 콜백 메서드에서는 데이터베이스 연결 풀 설정, 캐시 데이터 로드, 네트워크 소켓 열기, 또는 복잡한 내부 상태 검증과 같은 작업을 수행할 수 있다. 이 단계가 완료되어야 비로소 빈은 애플리케이션 내에서 안전하게 사용될 준비가 된 상태가 된다. 초기화 과정에서 예외가 발생하면 빈의 생성은 실패하게 되며, 컨테이너는 해당 빈을 사용 가능한 상태로 만들지 않는다.
3.2. 사용
3.2. 사용
스프링 IoC 컨테이너에 의해 생성 및 초기화된 스프링 빈은 애플리케이션에서 사용될 준비가 완료된다. 이 사용 단계는 빈의 생명주기에서 가장 긴 시간을 차지하는 핵심 단계이다. 컨테이너는 애플리케이션의 요청에 따라 필요한 빈을 조회하고, 빈들 간의 의존성 주입 관계를 통해 완성된 객체 그래프를 구성하여 비즈니스 로직을 실행한다.
사용 단계에서 빈은 주로 다른 빈에 주입되거나, 애플리케이션 코드에서 명시적으로 컨테이너로부터 조회되어 활용된다. 싱글톤 스코프로 설정된 빈의 경우, 컨테이너당 하나의 인스턴스만 존재하며, 이 인스턴스는 애플리케이션 전반에 걸쳐 공유되어 재사용된다. 이는 메모리 사용을 효율적으로 만들어 준다. 반면, 프로토타입 스코프의 빈은 요청할 때마다 새로운 인스턴스가 생성되어 반환된다.
빈의 사용은 의존성 주입 메커니즘을 통해 이루어진다. 컨테이너는 생성자 주입, 세터 주입, 필드 주입 등의 방식을 통해 빈이 필요로 하는 다른 빈이나 값을 자동으로 연결해 준다. 이를 통해 개발자는 객체 간의 복잡한 의존 관계를 직접 관리하지 않아도 되며, 느슨한 결합도를 유지한 채로 비즈니스 로직에 집중할 수 있다. 이 단계에서 빈은 정의된 모든 기능을 수행하며, 애플리케이션의 핵심 서비스를 제공한다.
3.3. 소멸
3.3. 소멸
소멸 단계는 스프링 빈의 생명주기에서 마지막 단계에 해당한다. 스프링 IoC 컨테이너가 종료되거나, 빈의 스코프가 끝나면 컨테이너는 관리하던 빈을 제거하기 위해 소멸 과정을 시작한다. 이 과정에서 빈은 사용하던 자원을 정리할 기회를 갖는다.
빈 소멸 시 특정 로직을 실행하도록 설정할 수 있다. XML 설정을 사용하는 경우 빈 정의에 destroy-method 속성을 지정하거나, 공통 인터페이스인 DisposableBean의 destroy() 메서드를 구현할 수 있다. 현대적인 자바 설정이나 컴포넌트 스캔 방식을 사용할 때는 @PreDestroy 어노테이션을 메서드에 부여하는 것이 일반적이다. 이렇게 지정된 메서드는 컨테이너가 빈을 제거하기 직전에 호출된다.
소멸 콜백의 실행 여부는 빈의 스코프에 따라 달라진다. 완전한 생명주기를 관리하는 싱글톤 빈의 경우 애플리케이션 컨텍스트 종료 시 소멸 메서드가 호출된다. 반면, 프로토타입 스코프의 빈은 생성과 의존성 주입까지 컨테이너가 관리할 뿐, 이후의 생명주기 관리는 클라이언트 코드에 맡기기 때문에 컨테이너에 의해 소멸 콜백이 실행되지 않는다는 점에 유의해야 한다.
4. 스코프
4. 스코프
4.1. 싱글톤
4.1. 싱글톤
싱글톤은 스프링 빈의 기본 스코프이다. 이 스코프를 가지는 빈은 스프링 IoC 컨테이너 내에서 단 하나의 인스턴스만 생성되어 관리된다. 컨테이너가 시작될 때 생성되거나, 처음 요청되는 시점에 지연 생성될 수 있으며, 이후 동일한 빈을 요청할 때마다 미리 생성된 동일한 객체 인스턴스가 반환된다. 이는 애플리케이션 전역에서 상태를 공유해야 하는 서비스 객체나 DAO와 같은 객체에 적합한 방식이다.
싱글톤 스코프의 빈은 의존성 주입을 통해 다른 빈에 주입될 때, 주입받는 모든 대상이 동일한 인스턴스를 참조하게 된다. 이는 메모리 사용을 절약하고, 객체 생성 비용을 줄이는 장점이 있다. 그러나 여러 스레드가 동시에 하나의 인스턴스에 접근할 수 있으므로, 빈의 상태를 변경하는 경우 스레드 안전성을 고려하여 설계해야 한다.
싱글톤 스코프는 명시적으로 지정하지 않아도 적용되는 기본값이다. XML 설정에서는 scope 속성을 "singleton"으로 명시하거나 생략할 수 있으며, 자바 설정 클래스나 컴포넌트 스캔을 통한 어노테이션 기반 설정에서는 @Scope("singleton") 또는 @Scope 어노테이션을 생략함으로써 적용된다. 이는 프로토타입 스코프나 웹 관련 스코프와 대비되는 특징이다.
4.2. 프로토타입
4.2. 프로토타입
프로토타입 스코프는 스프링 빈의 기본 스코프인 싱글톤과 대비되는 개념이다. 프로토타입 스코프로 정의된 빈은 스프링 IoC 컨테이너에 요청할 때마다 새로운 인스턴스가 생성되어 반환된다. 즉, 컨테이너는 프로토타입 빈의 인스턴스를 생성하고 의존성을 주입한 후, 이후의 생명주기 관리는 클라이언트에게 위임한다.
이 스코프는 상태를 유지해야 하거나 다수의 독립적인 객체 인스턴스가 필요한 경우에 적합하다. 예를 들어, 각 HTTP 요청마다 별도의 데이터를 처리해야 하는 객체나, 사용자 세션별로 상태가 달라지는 객체를 구현할 때 활용될 수 있다. 싱글톤 빈이 애플리케이션 전역에서 하나의 인스턴스를 공유하는 반면, 프로토타입 빈은 매번 새로운 인스턴스를 제공함으로써 객체 간의 상태 간섭을 방지한다.
프로토타입 빈은 @Scope("prototype") 어노테이션을 사용하여 명시적으로 지정할 수 있으며, XML 설정이나 자바 설정 클래스를 통해서도 정의 가능하다. 주의할 점은 프로토타입 빈이 싱글톤 빈에 주입될 경우, 싱글톤 빈의 생성 시점에 한 번만 주입되므로 프로토타입 빈의 새로운 인스턴스를 계속 얻고자 한다면 추가적인 방법이 필요하다.
프로토타입 스코프의 사용은 메모리 관리 측면에서 고려해야 한다. 컨테이너가 생명주기 후반부를 관리하지 않으므로, 빈 인스턴스 사용이 끝난 후의 정리 작업은 클라이언트 코드나 별도의 콜백 메커니즘을 통해 처리해야 할 수 있다. 따라서 신중한 설계 없이 남용할 경우 자원 누수의 원인이 될 수 있다.
4.3. 웹 관련 스코프
4.3. 웹 관련 스코프
스프링 프레임워크의 빈은 기본적으로 싱글톤 스코프로 관리되지만, 웹 애플리케이션을 개발할 때는 요청이나 세션과 같은 웹 특정 생명주기에 맞춰 관리해야 할 필요가 있다. 이를 위해 스프링은 웹 관련 스코프를 제공한다. 가장 일반적으로 사용되는 것은 요청 스코프와 세션 스코프이며, 웹소켓과 같은 긴 생명주기를 위한 애플리케이션 스코프도 존재한다.
요청 스코프는 하나의 HTTP 요청이 시작될 때 생성되고, 요청이 끝나면 소멸된다. 이는 주로 사용자의 한 번의 요청 처리 동안만 유지되어야 하는 상태 정보를 담는 객체에 적합하다. 세션 스코프는 사용자의 HTTP 세션이 시작될 때 생성되어 세션이 종료될 때까지 유지된다. 주로 로그인한 사용자 정보나 장바구니와 같은 세션 단위 데이터를 관리하는 데 사용된다. 이러한 스코프는 XML 설정이나 어노테이션을 통해 지정할 수 있다.
웹 관련 스코프를 사용할 때 주의할 점은, 이 빈들이 기본 싱글톤 빈보다 짧은 생명주기를 가지므로 의존 관계 주입 시 프록시 객체를 통해 접근해야 한다는 것이다. 스프링은 @Scope 어노테이션에 proxyMode 속성을 설정하여 이를 처리한다. 이렇게 하면 싱글톤 빈이 요청이나 세션 스코프의 빈을 참조할 때 실제 빈 인스턴스 대신 프록시를 주입받아, 실제 요청이 발생할 때마다 올바른 대상 인스턴스에 접근할 수 있게 된다.
5. 등록 방법
5. 등록 방법
5.1. XML 설정
5.1. XML 설정
XML 설정은 스프링 프레임워크 초기부터 사용된 스프링 빈을 정의하는 고전적인 방법이다. 애플리케이션 컨텍스트의 구성 정보를 XML 파일에 명시적으로 작성하는 방식으로, 주로 applicationContext.xml 또는 beans.xml과 같은 이름의 파일을 사용한다. 이 파일은 클래스패스나 파일 시스템 경로에 위치시키며, 스프링 IoC 컨테이너가 시작될 때 이 파일을 읽어 내부에 정의된 빈들을 생성하고 관리한다.
XML 설정에서는 <beans>를 루트 엘리먼트로 사용하며, 그 내부에 개별 빈을 정의하는 <bean> 엘리먼트를 배치한다. 각 <bean> 엘리먼트는 id 또는 name 속성으로 빈의 고유 식별자를 지정하고, class 속성으로 해당 빈의 완전한 클래스 이름(패키지 경로 포함)을 명시한다. 또한 scope 속성을 통해 싱글톤이나 프로토타입과 같은 빈의 스코프를 설정할 수 있다.
의존성 주입은 XML 설정에서도 핵심적으로 지원된다. 생성자 주입은 <constructor-arg> 엘리먼트를 사용하여 구현하며, 세터 주입은 <property> 엘리먼트를 통해 수행한다. <property> 엘리먼트의 name 속성은 세터 메서드 이름을, value 속성은 기본 타입이나 문자열 값을, ref 속성은 다른 빈 객체에 대한 참조를 지정할 때 사용한다. 이를 통해 빈들 간의 관계를 XML 선언만으로 구성할 수 있다.
XML 설정의 주요 장점은 설정 정보가 자바 소스 코드와 완전히 분리된다는 점이다. 이는 빈의 구성이나 클래스 경로를 변경해야 할 때 애플리케이션을 재컴파일하지 않고도 XML 파일만 수정하여 반영할 수 있게 한다. 그러나 설정이 복잡해질수록 파일의 크기가 커지고 가독성이 떨어질 수 있으며, 오타 등의 오류가 발생하기 쉬운 단점도 있다. 이후 등장한 어노테이션 기반 설정과 자바 설정 클래스에 비해 더 장황(verbose)한 방식으로 평가된다.
5.2. 어노테이션
5.2. 어노테이션
스프링 프레임워크에서는 어노테이션을 활용하여 스프링 빈의 등록과 관리를 선언적이고 편리하게 할 수 있다. 이러한 어노테이션 기반 설정은 복잡한 XML 설정을 대체하며, 자바 코드 내에서 직접 구성 정보를 명시할 수 있어 개발 생산성을 크게 향상시킨다.
주요 어노테이션은 크게 빈 등록을 위한 어노테이션과 의존성 주입을 위한 어노테이션으로 구분된다. 빈 등록을 위해 사용되는 핵심 어노테이션은 @Component이다. 이 어노테이션이 부여된 클래스는 컴포넌트 스캔 과정에서 자동으로 탐지되어 스프링 IoC 컨테이너에 빈으로 등록된다. @Component를 세분화한 @Controller, @Service, @Repository 어노테이션도 있으며, 각각 프레젠테이션 계층, 비즈니스 로직 계층, 데이터 접근 계층의 구성 요소를 표시하는 데 사용되어 계층별 아키텍처를 명확하게 표현하는 데 도움을 준다.
의존성 주입을 처리하기 위한 가장 대표적인 어노테이션은 @Autowired이다. 이 어노테이션을 생성자, 세터 메서드, 또는 필드에 부여하면 스프링 컨테이너가 자동으로 해당 타입의 빈을 찾아 연결해 준다. 동일한 타입의 빈이 여러 개 존재할 경우 @Qualifier 어노테이션을 함께 사용하여 구체적인 빈의 이름을 지정함으로써 주입 대상을 명시할 수 있다.
또한, 자바 설정 클래스를 이용한 빈 등록 방식에서는 @Configuration과 @Bean 어노테이션이 중요한 역할을 한다. @Configuration이 붙은 클래스는 빈 설정의 정보를 담고 있으며, 그 내부의 @Bean이 붙은 메서드는 반환되는 객체를 스프링 빈으로 등록하도록 지시한다. 이 방식은 외부 라이브러리의 클래스를 빈으로 등록해야 할 때나 빈 생성 과정에 특별한 로직이 필요할 때 유용하게 사용된다.
5.3. 자바 설정 클래스
5.3. 자바 설정 클래스
자바 설정 클래스는 XML 설정 파일을 대체하여 순수 자바 코드로 스프링 빈을 정의하고 스프링 IoC 컨테이너를 구성하는 현대적인 방법이다. @Configuration 어노테이션이 붙은 클래스를 사용하며, 이 클래스 내부에서 @Bean 어노테이션이 붙은 메서드를 통해 빈을 등록한다. 이 방식은 리팩토링과 타입 안정성 측면에서 XML 설정보다 유리하며, 자바의 강력한 문법을 활용해 복잡한 빈 생성 로직을 구현할 수 있다는 장점이 있다.
@Configuration 클래스 내부의 @Bean 메서드는 일반적으로 빈의 인스턴스를 생성하여 반환한다. 스프링 IoC 컨테이너는 이 메서드를 호출하고 그 반환값을 빈으로 관리한다. 메서드 내에서는 생성자 호출, 팩토리 메서드 사용, 다른 빈에 대한 의존성 주입 등 필요한 초기화 작업을 자유롭게 수행할 수 있다. 또한 @Bean 메서드가 다른 @Bean 메서드를 호출할 경우, 스프링은 기본적으로 싱글톤 스코프를 보장하기 위해 적절한 프록시를 적용한다.
자바 설정 방식은 스프링 부트의 등장과 함께 사실상 표준 설정 방식으로 자리 잡았다. 스프링 부트의 자동 구성(@EnableAutoConfiguration) 메커니즘도 내부적으로 수많은 @Configuration 클래스를 통해 이루어진다. 개발자는 @Configuration 클래스를 사용해 애플리케이션 컨텍스트를 완전히 코드로 제어할 수 있으며, 프로파일(@Profile)이나 조건부 빈(@Conditional) 등과 결합하여 환경에 따른 유연한 구성을 가능하게 한다.
6. 의존성 주입
6. 의존성 주입
6.1. 생성자 주입
6.1. 생성자 주입
생성자 주입은 의존성 주입 방식 중 하나로, 스프링 빈이 필요로 하는 의존 객체를 생성자를 통해 전달받는 방법이다. 이 방식은 스프링 프레임워크에서 권장하는 방식으로, 객체가 생성되는 시점에 필요한 모든 의존 관계가 확정되도록 보장한다.
생성자 주입을 사용하면 불변성을 유지할 수 있다. 즉, 의존 객체를 담는 필드를 final로 선언하여 빈이 생성된 후에는 의존 관계가 변경되지 않도록 할 수 있다. 이는 스레드 안전성을 높이고, 객체의 상태를 예측 가능하게 만드는 데 도움이 된다. 또한 생성자를 통해 명시적으로 의존성을 요구함으로써, NullPointerException과 같은 런타임 오류를 방지하고 테스트 용이성을 향상시킨다.
스프링 4.3 버전부터는 생성자가 하나만 존재하고, 그 생성자의 매개변수가 모두 스프링 빈으로 등록되어 있다면 @Autowired 어노테이션을 생략할 수 있다. 하지만 명시적으로 @Autowired를 생성자에 붙여 의존성 주입을 명시하는 것도 일반적인 관행이다. 생성자 주입은 XML 설정 파일에서 <constructor-arg> 요소를 사용하거나, 자바 설정 클래스에서 직접 생성자를 호출하는 방식으로도 구현할 수 있다.
생성자 주입은 필수적인 의존 관계를 설정할 때 특히 유용하다. 모든 의존성이 객체 생성 시점에 주입되므로, 빈이 완전한 상태로 초기화된다는 장점이 있다. 이는 순환 참조 문제를 컴파일 타임이나 애플리케이션 구동 시점에 조기에 발견할 수 있게 해주며, 의존 관계의 명확성을 높인다.
6.2. 세터 주입
6.2. 세터 주입
세터 주입은 의존성 주입 방식 중 하나로, 스프링 프레임워크가 빈 객체에 필요한 의존성을 해당 객체의 세터 메서드를 통해 설정하는 방법이다. 객체가 생성된 후에 의존 관계를 설정할 수 있으며, 선택적 의존성을 주입할 때 유용하다. XML 설정에서는 <property> 요소를 사용하여, 자바 설정 클래스에서는 @Bean 메서드 내에서 세터를 호출하는 방식으로 구현한다.
이 방식은 객체 생성과 의존성 설정을 분리할 수 있어 유연성이 높다는 장점이 있다. 또한 세터 메서드의 이름을 통해 어떤 의존성이 주입되는지 명시적으로 알 수 있다. 하지만 객체가 완전히 초기화되지 않은 상태(의존성이 주입되지 않은 상태)로 사용될 가능성이 있으며, 불변성을 보장하기 어려울 수 있다는 단점도 있다.
6.3. 필드 주입
6.3. 필드 주입
필드 주입은 의존성 주입 방식 중 하나로, 스프링 빈의 필드에 직접 @Autowired 어노테이션을 선언하여 의존성을 주입하는 방법이다. 클래스 내부의 필드 선언부에 어노테이션을 추가하기만 하면 되므로 코드가 매우 간결해지는 장점이 있다. 이 방식은 생성자 주입이나 세터 주입과 달리 별도의 생성자나 설정 메서드를 작성할 필요가 없다.
그러나 필드 주입은 몇 가지 단점을 가지고 있다. 첫째, 의존 관계를 외부에서 변경하기가 불가능하다는 점이다. 리플렉션을 사용하지 않는 한, 단위 테스트 시에 목 객체를 주입하거나 의존성을 교체하기 어렵다. 둘째, 스프링 IoC 컨테이너에 강하게 결합되어 있어, 순수 자바 객체로는 인스턴스화할 수 없다. 이는 프레임워크 의존성을 높인다.
현대 스프링 개발에서는 이러한 단점들로 인해 생성자 주입을 권장하는 추세이다. 생성자 주입은 불변성을 보장하고, 순환 참조를 컴파일 타임에 방지하며, 테스트 용이성이 뛰어나기 때문이다. 따라서 필드 주입은 주로 프로토타입 스코프의 빈이나, 레거시 코드 유지보수, 또는 간단한 설정 클래스에서 제한적으로 사용된다.
7. 관련 어노테이션
7. 관련 어노테이션
7.1. @Component 및 세부 어노테이션
7.1. @Component 및 세부 어노테이션
스프링 프레임워크에서 빈을 등록하는 주요 방법 중 하나는 컴포넌트 스캔을 이용하는 것이다. 컴포넌트 스캔은 클래스패스를 탐색하여 특정 어노테이션이 부여된 클래스를 자동으로 찾아내고, 이를 스프링 IoC 컨테이너에 빈으로 등록하는 기능이다. 이 방식을 사용하면 XML이나 자바 설정 파일에 각 빈을 일일이 선언하지 않아도 되므로 설정이 간소화된다.
컴포넌트 스캔의 대상이 되는 가장 기본적인 어노테이션이 @Component이다. 이 어노테이션이 클래스에 선언되면, 스프링은 해당 클래스를 빈 정의의 원천으로 인식하고 애플리케이션 컨텍스트에 빈으로 등록한다. @Component는 계층 구조상 가장 상위에 위치한 일반적인 스테레오타입 어노테이션으로 간주된다.
실제 개발에서는 보다 구체적인 역할을 명시하기 위해 @Component를 특화한 세부 어노테이션들을 주로 사용한다. 대표적으로 @Repository는 데이터 접근 계층(DAO)을, @Service는 비즈니스 로직 계층(서비스)을, @Controller는 프레젠테이션 계층(웹 컨트롤러)을 표시하는 데 사용된다. 이들은 모두 내부적으로 @Component를 포함하고 있어 컴포넌트 스캔의 대상이 된다.
이러한 계층별 어노테이션을 사용하는 주된 이점은 스프링 AOP와 같은 프레임워크의 부가 기능이 특정 계층에 자동으로 적용될 수 있도록 하는 것이다. 예를 들어, @Repository 어노테이션이 부여된 클래스에서는 데이터 접근 중 발생하는 특정 예외가 스프링의 통일된 DataAccessException으로 변환되는 등의 처리가 가능해진다. 따라서 클래스의 역할에 맞는 가장 구체적인 어노테이션을 사용하는 것이 권장된다.
7.2. @Autowired
7.2. @Autowired
@Autowired는 스프링 프레임워크에서 제공하는 어노테이션으로, 스프링 IoC 컨테이너가 관리하는 스프링 빈 간의 의존성 주입을 자동으로 수행하도록 지시한다. 이 어노테이션을 생성자, 세터 메서드, 필드 또는 일반 메서드에 적용할 수 있으며, 컨테이너는 해당 타입에 맞는 빈을 찾아 자동으로 연결해 준다. 이를 통해 개발자는 복잡한 XML 설정 파일 없이도 객체 간의 의존 관계를 간결하게 설정할 수 있다.
@Autowired의 주요 동작 방식은 타입 기반의 의존성 주입이다. 스프링 IoC 컨테이너는 어노테이션이 붙은 대상의 타입(예: SomeService)을 확인하고, 자신이 관리하는 빈 중에서 그 타입에 할당 가능한 빈을 찾아 주입한다. 만약 해당 타입의 빈이 정확히 하나만 존재하면 그것을 사용한다. 타입이 일치하는 빈이 여러 개일 경우 추가적인 한정자가 필요하며, 이때는 @Qualifier 어노테이션을 함께 사용하여 특정 빈의 이름을 지정할 수 있다.
사용 위치에 따라 주입 방식이 나뉜다. 생성자에 적용하면 생성자 주입이, 세터 메서드에 적용하면 세터 주입이, 필드에 직접 적용하면 필드 주입이 이루어진다. 특히 생성자 주입은 불변 객체를 보장하고 순환 의존성을 초기에 발견할 수 있어 권장되는 방식이다. @Autowired의 required 속성을 false로 설정하면, 주입할 빈이 존재하지 않아도 예외를 발생시키지 않도록 할 수 있다.
@Autowired는 스프링의 컴포넌트 스캔 기능과 결합되어 자동 의존성 주입의 핵심 매커니즘으로 작동한다. @Component, @Service, @Repository 등의 스테레오타입 어노테이션으로 표시된 클래스들이 빈으로 등록되면, 이들 사이의 의존 관계는 대부분 @Autowired를 통해 자동으로 해결된다. 이는 설정 정보를 최소화하고 관심사의 분리를 실현하는 스프링의 핵심 철학을 구현하는 데 기여한다.
7.3. @Qualifier
7.3. @Qualifier
@Qualifier는 스프링 프레임워크에서 동일한 타입의 빈이 여러 개 존재할 때, 특정 빈을 명시적으로 지정하여 의존성 주입을 수행하기 위해 사용하는 어노테이션이다. 주로 @Autowired와 함께 사용되며, 빈의 이름이나 한정자(qualifier) 값을 기준으로 주입 대상을 구체화한다.
이 어노테이션은 인터페이스에 여러 구현체가 존재하거나, 동일한 클래스 타입의 빈이 여러 개 정의된 상황에서 유용하다. 예를 들어, PaymentService라는 인터페이스와 이를 구현한 CreditCardService와 PayPalService 두 개의 빈이 있다고 가정할 때, @Autowired만으로는 어떤 구현체를 주입해야 할지 알 수 없다. 이때 @Qualifier를 사용하여 "creditCard" 또는 "paypal"과 같은 식별자를 지정함으로써 원하는 빈을 선택할 수 있다.
@Qualifier는 생성자 주입, 세터 주입, 필드 주입 등 다양한 주입 방식에 적용 가능하다. 또한, 빈을 정의할 때 @Component나 @Bean 어노테이션과 함께 직접 한정자 값을 부여할 수도 있으며, 이를 통해 코드의 의도를 더 명확하게 표현할 수 있다. @Primary 어노테이션을 사용하여 기본 주입 빈을 지정하는 방법도 있지만, 보다 정밀한 제어가 필요할 때는 @Qualifier가 선호된다.
이 어노테이션은 의존성 주입 과정에서 발생할 수 있는 모호성을 해결하고, 애플리케이션의 구성 요소 간 명시적인 연결을 가능하게 함으로써 유지보수성과 가독성을 높이는 데 기여한다.
8. 여담
8. 여담
스프링 빈은 스프링 프레임워크의 핵심 개념으로, 의존성 주입과 제어의 역전 원칙을 구현하는 기본 단위이다. 자바 기반의 엔터프라이즈 애플리케이션 개발에서 객체의 생성, 조립, 관리를 애플리케이션 코드가 아닌 스프링 IoC 컨테이너에 위임함으로써 느슨한 결합도와 높은 테스트 용이성을 제공한다.
빈의 기본 스코프는 싱글톤으로, 컨테이너 내에서 하나의 인스턴스만 생성되어 재사용된다. 이는 메모리 사용을 효율적으로 하기 위함이다. 반면, 프로토타입 스코프는 요청마다 새로운 인스턴스를 생성하여 제공한다. 또한 웹 애플리케이션을 위한 리퀘스트 스코프, 세션 스코프, 애플리케이션 스코프 등도 지원한다.
빈을 등록하는 방법은 진화해 왔다. 초기에는 XML 설정 파일을 사용해 명시적으로 빈을 정의했으나, 어노테이션 기반의 컴포넌트 스캔 (@Component, @Service, @Repository 등)이 등장하며 설정이 간소화되었다. 최근에는 자바 설정 클래스(@Configuration)를 사용하는 방식이 선호되는 추세이다.
의존성을 주입하는 방법으로는 생성자 주입, 세터 주입, 필드 주입이 있다. 그중 생성자 주입은 빈 객체가 불변성을 갖고 필수 의존 관계를 명확히 할 수 있어 권장되는 방식이다. @Autowired 어노테이션을 사용하면 컨테이너가 자동으로 적합한 빈을 찾아 주입하며, @Qualifier를 통해 특정 빈을 지정할 수도 있다.
